﻿using System.Collections.Generic;
using MagicWorld.DDD.Domain.Types.Exceptions;

namespace MagicWorld.DDD.Domain.Event
{
    public class EventBus
    {
        // 注册器
        private static EventRegistry invokerRegistry;

        // 事件分发器
        private static EventDispatcher dispatcher;

        // 异步事件分发器
        private static EventDispatcher asyncDispatcher;

        public EventBus()
        {
            invokerRegistry = new EventRegistry(this);
            dispatcher = new EventDispatcher(ExecutorFactory.DirectExecutor());
            asyncDispatcher = new EventDispatcher(ExecutorFactory.ThreadPoolExecutor());
        }

        /// <summary>
        /// 事件分发
        /// </summary>
        /// <param name=""></param>
        /// <returns></returns>
        public static bool Dispatch(IEvent e)
        {
            return Dispatch(e, dispatcher);
        }

        /// <summary>
        /// 异步事件分发
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        public bool DispatchAsync(IEvent e)
        {
            return Dispatch(e, asyncDispatcher);
        }

        /// <summary>
        /// 内部事件分发
        /// </summary>
        /// <param name="e"></param>
        /// <param name="dispatcher"></param>
        /// <returns></returns>
        private static bool Dispatch(IEvent e, EventDispatcher dispatcher)
        {
            CheckEvent(e);

            // 1.获取事件数组
            HashSet<Invoker> invokers = invokerRegistry.GetInvokers(e);

            // 2.一个事件可以被监听 N 次，不关心调用结果
            dispatcher.Dispatch(e, invokers);
            return true;
        }

        /// <summary>
        /// 事件总线注册
        /// </summary>
        /// <param name="listener">监听者</param>
        public static void Register(object listener)
        {
            if (listener == null)
            {
                throw new IllegalArgumentException("listener can not be null!");
            }
            invokerRegistry.Register(listener);
        }

        private static void CheckEvent(IEvent e)
        {
            if (e == null)
            {
                throw new IllegalArgumentException("event");
            }
        }
    }
}